home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DDJMAG / DDJ9207.ZIP / QUICKT.ZIP / NOTES.QT
Text File  |  1992-05-26  |  21KB  |  380 lines

  1.  
  2. _PROGRAMMING QUICKTIME_
  3. by Aaron Walsh
  4.  
  5.  
  6. PROGRAMMER NOTES:
  7.  
  8. Once initialized, the user is asked to select a QuickTime 
  9. movie file from disk. GetMovie() demonstrates the use of the new 
  10. StandardGetFilePreview() routine. This call provides the user 
  11. with a thumbnail view (preview) of selected files, as mentioned 
  12. earlier. Under System 7, use the call: void 
  13. StandardGetFilePreview (FileFilterProcPtr fileFilter, short 
  14. numTypes, SFTypeList typeList,     StandardFileReply *fReply).
  15.      StandardGetFilePreview() corresponds to the older 
  16. StandardGetFile() routine documented in Inside Macintosh, Volume 
  17. VI with the exception that it provides file preview capabilities. 
  18. After execution, fReply.good is used to determine if a valid 
  19. selection was made, or if the Cancel button was hit. If a valid 
  20. selection was made, fReply contains various file information for 
  21. the selected file. Under System 7 this information is returned in 
  22. the form of an FSSpec, which is used to reference the movie file 
  23. in subsequent calls to the Movie Toolbox. Under System 6, 
  24. StandardGetFilePreview() is not available. Instead, 
  25. SFGetFilePreview() is used and an FSSpec is manually generated 
  26. from the older style reply record.
  27.      With the file selected, we enter PlayMovie(), which uses the 
  28. FSSpec record to access the movie file and prepare it for 
  29. playing. Prior to being played, the movie file must be opened 
  30. using OSErr OpenMovieFile (const FSSpec *fileSpec, short 
  31. *resRefNum, char permission) where fileSpec contains the volume 
  32. reference number, directory ID and file name of our selected 
  33. movie. OpenMovieFile() uses this information to open the movie 
  34. file's resource fork with the requested permission. Use 
  35. permission of 0 (zero) when playing a movie. If the movie file is 
  36. opened with no error, a reference number to its resource fork is 
  37. returned in resRefNum. We use resRefNum to create a movie from 
  38. the opened file with OSErr NewMovieFromFile (Movie *theMovie, 
  39. short resRefNum, short *resId, StringPtr resName, short 
  40. newMovieFlags, Boolean *dataRefWasChanged). 
  41.      Given  a resource reference number in resRefNum and nil in 
  42. both resId and resName, NewMovieFromFile() locates the first 
  43. 'moov' resource in the open resource fork and resolves its data 
  44. references. The resulting movie is accessible through theMovie.  
  45. If we wanted to make a movie from a specific 'moov' resource, we 
  46. would utilize the resId parameter. Instead, we pass nil, which 
  47. tells NewMovieFromFile() to use the first 'moov' resource found.
  48.      Since we will neither change nor display the name of the 
  49. 'moov' resource, pass nil for resName. The newMovieFlags and    
  50. dataRefWasChanged provide a mechanism for further controlling the 
  51. properties of the newly created movie. We will not utilize these 
  52. parameters when playing our movie.
  53.      After creating a movie from the file reference, prepare the 
  54. display window in which it will ultimately be viewed. Obtain the 
  55. movie's bounding box (a rectangle) with GetMovieBox(). The top 
  56. left corner of the bounding box should be set to [0,0] using the 
  57. OffsetRect() call. This ensures proper placement of the movie 
  58. within a display window, created with a call to NewCWindow(). 
  59. Passing the movie's bounding box to NewCWindow() ensures that the 
  60. display window is the proper height and width to accommodate our 
  61. movie with void GetMovieBox (Movie m, Rect *boxRect) and void 
  62. SetMovieBox (Movie m,const Rect *boxRect). 
  63.      A call to SetPort() makes our display window the current 
  64. graphics port. A subsequent call to SetMovieGWorld() ties the 
  65. movie's GWorld to that of our display window. When the movie is 
  66. played, it will appear in our display window. Pass nil for both 
  67. port and gdh to set the movie's GWorld to the current port and 
  68. graphics device, void SetMovieGWorld (Movie m, CGrafPtr port, 
  69. GDHandle gdh). After preparing the movie display window, it is 
  70. time to add the standard movie controller. MakeMovieController() 
  71. shows how to use the Component Manager to access the default 
  72. movie controller. The Movie Toolbox is then called upon to attach 
  73. the controller to the movie display window.
  74.      As mentioned earlier, components register their individual 
  75. capabilities with the system. At startup, the Component Manager 
  76. locates and registers all components in files of type 'thng' 
  77. located in the Extensions Folder under System 7, or in the System 
  78. Folder itself under System 6. An application can then request the 
  79. use of a reqistered component.  
  80.      When an application wishes to use a component (which can 
  81. range in functionality from decompression components to media 
  82. handlers), it fills out a ComponentDescription record. The fields 
  83. of a ComponentDescription describe what capabilities are needed, 
  84. meaning you ask for a component by function rather than by name.  
  85. If the system locates a suitable component, its reference is 
  86. passed to the application. The reference itself does not provide 
  87. the application with immediate access to the component, however. 
  88. Pass the reference to OpenComponent(), which creates an instance  
  89. of the component. The component instance provides an application 
  90. with an open line of communication to the actual component, which 
  91. may be designed to be accessed multiple times simultaneously.
  92.      Components are classified by type. We request the basic 
  93. player component, the standard movie controller, by passing 
  94. "play" in the componentType field of the ComponentDescription. 
  95. The remainder of the ComponentDescription fields (SubType, 
  96. Manufacturer, Flags, and FlagsMask) are left blank. These fields 
  97. are used to further describe a particular component, should you 
  98. need access to a specific component. FindNextComponent() reads 
  99. the ComponentDescription and attempts to locate a corresponding 
  100. component with Component FindNextComponent (Component aComponent, 
  101. ComponentDescription *looking).
  102.      Passing 0 (zero) in aComponent tells the Component Manager 
  103. to return the first match it finds. During a more exhaustive 
  104. component search, you might pass the last component found back to 
  105. FindNextComponent() in which case the search will continue from 
  106. that component on, returning the next match in the component 
  107. list. Remember that this call alone does not return an 
  108. immediately accessible component. Use OpenComponent(), which 
  109. returns an instance to a component when passed a valid reference.
  110.      Once opened, the controller component is attached to the 
  111. movie display window. This is done with a call to 
  112. MCNewAttachedController(), passing the controller instance, the 
  113. movie and its display window (movieWindow), and a point 
  114. specifying the display window's upperleft corner. This function 
  115. associates the controller with our movie, attaching it to the 
  116. display window using ComponentResult MCNewAttachedController 
  117. (MovieController mc, Movie m,WindowPtr w, Point where).
  118.      We then resize the display window to accommodate the newly 
  119. attached controller. This minor adjustment is necessary, for the 
  120. display window is only large enough to display the movie itself 
  121. and no more. Resizing the window to take into account the 
  122. controller bounding box permits both controller and display 
  123. window to be visible at the same time. If you are not able to see 
  124. the controller when the movie is displayed, check to make sure 
  125. the display window has been correctly resized. 
  126. ShowMovieController() illustrates the proper steps.
  127.      After adjusting the display window to accommodate its new 
  128. controller, we prepare the movie for play. To ensure that the 
  129. movie starts playing at the very beginning, "rewind" the movie 
  130. with a call to GoToBeginningOfMovie(). 
  131.      PrerollMovie() instructs the Movie Toolbox to activate the 
  132. movie's media handlers prior to play time, allowing segments of 
  133. media data to be preloaded into memory. The overall effect is 
  134. smoother play, since disk access is reduced during playback.  
  135. Other techniques involve preloading specific portions of the 
  136. movie into RAM with calls to LoadMovieIntoRam(), 
  137. LoadTrackIntoRam(), and LoadMediaIntoRam(). These calls give a 
  138. noticeable performance increase when a movie demands significant 
  139. amounts of random access during playback with void 
  140. GoToBeginningOfMovie (Movie m) and OSErr PrerollMovie (Movie m, 
  141. TimeValue time, Fixed rate).
  142.      Since only "active" movies and tracks are serviced by the 
  143. Movie Toolbox, it is necessary to activate our entire movie with 
  144. a call to SetMovieActive(). A similar call, SetTrackEnabled(), 
  145. operates on individual tracks. A movie or track is made active by 
  146. passing TRUE, inactive by passing FALSE. The active status of a 
  147. movie or track can be checked with GetMovieActive() and 
  148. GetTrackEnabled().
  149.  
  150. void SetMovieActive (Movie m, Boolean active)
  151.  
  152. Having prepared the movie, we are ready to being play.    A small 
  153. event-loop makes it possible to play and control the movie via 
  154. the movie controller component.    While the movie is not finished 
  155. playing (!IsMovieDone()), we get the next event and pass it to 
  156. MCIsPayerEvent() which handles all events for a movie controller.  
  157. Normally called from within an application's main event loop, 
  158. MCIsPayerEvent() returns a long integer set to 1 if the 
  159. controller component handled the event, 0 (zero) otherwise.  If 
  160. the controller component handles the event, your main event-loop 
  161. should skip the remainder of its event loop and wait for the next 
  162. event.  If 0 (zero) is returned, your application should process 
  163. the event in its normal manner.
  164.  
  165. ComponentResult MCIsPlayerEvent(MovieController mc,const 
  166. EventRecord *e)
  167.  
  168. The movie controller component    takes all the necessary actions 
  169. for supporting the movie controller and its associated movie.  
  170. All aspects of movie play are controlled through the controller 
  171. component, including volume control, update events, and 
  172. MultiFinder suspend and resume events.  Your application need not 
  173. be concerned with advancing the movie during play, synchronizing 
  174. the sound track or even updating the movie window.  
  175. MCIsPayerEvent() ensures these concerns are handled by the movie 
  176. controller component when passed the corresponding event.  If you 
  177. wish to alter    or enhance this process, you may set up an action 
  178. filter which allows your application to perform custom processing 
  179. for a movie controller event.  An action filter is installed with 
  180. a call to MCSetActionFilter().  
  181.      Once our small event loop is entered, the movie is displayed 
  182. on screen.  Click on the controller play button to set the movie 
  183. in motion .  The movie will begin playing active tracks, 
  184. displaying video and playing sound if available.  Use the 
  185. controller to fast forward, reverse direction of play, pause the 
  186. movie or change the volume.  Once a movie has finished playing 
  187. (that is, once all track media have been played to end), its 
  188. storage is freed and references to the movie and controller are 
  189. closed.
  190.      The main loop is designed to repeat the entire movie playing 
  191. process until the cancel button in the Standard File Preview 
  192. dialog is selected.  At that time, ExitMovies() is called.  
  193. ExitMovies() instructs the Movie Toolbox to release all private 
  194. storage allocated for your application when EnterMovies() was 
  195. called.  You must be sure to close all open component connections 
  196. (movie controllers, sequence grabbers, etc.) prior to calling 
  197. ExitMovies().  If a System Error is generated when calling 
  198. ExitMovies(), it is likely that a component connection was not 
  199. properly closed or your movie was not disposed of prior to the 
  200. call.
  201.  
  202.      OSErr CreateMovieFile (const FSSpec *fileSpec, OSType 
  203. creator, ScriptCode scriptTag, long createMovieFileFlags,                 
  204. short *resRefNum, Movie *newMovie)
  205.  
  206.      The creator parameter determines which application will be 
  207. launched when the movie file is double-clicked or opened from the 
  208. Finder.  This is normally set to the creator code of the 
  209. application making the movie.  Since MovieMaker can only create 
  210. movies, not play them, we pass the creator code for MoviePlayer 
  211. ('MPLA'). 
  212.      To specify a specific script for a movie (used in 
  213. localization, the process of adapting an application to a 
  214. specific language or culture), use the scripTag parameter.    
  215. MovieMaker does not utilize scripts, and so passes 0 (zero) for 
  216. this parameter.
  217.      Various file creation options are available using the 
  218. createMovieFileFlags parameter.  Passing 
  219. createMovieFileDeleteCurFile instructs the Movie Toolbox to 
  220. delete any existing file currently specified by the fileSpec  
  221. parameter before creating a new one.  This ensures that our movie 
  222. file is created from scratch.  Several options are available when 
  223. creating a new file, ranging from movie control to track access.  
  224. Consult Apple's QuickTime documentation for a detailed 
  225. description of this parameter.
  226.      If CreateMovieFile() is successful newMovie  will point to a 
  227. movie in memory and resRefNum  will contain the reference number 
  228. of its resource fork.  If unsucessful, an appropriate OSErr is 
  229. returned by the function and newMovie is set to nil.
  230.  
  231. Track and Media
  232. NewMovieTrack() combined with NewTrackMedia() add a single track 
  233. and associated media to our movie.  NewMovieTrack() should be 
  234. followed by NewTrackMedia() since a movie track without a media 
  235. is possible but serves no purpose:
  236.      
  237. Track NewMovieTrack (Movie m, Fixed width, Fixed height, short 
  238. trackVolume)
  239.  
  240. Media NewTrackMedia (Track t, OSType mediaType, TimeScale 
  241. timeScale, Handle dataRef, OSType dataRefType)
  242.  
  243. The width and height parameters of NewMovieTrack() define the 
  244. track display rectangle in relation to the movie rectangle.  When 
  245. creating a track that is not displayed on screen, such as a sound 
  246. track, pass 0 (zero) for both parameters. trackVolume  specifies 
  247. the playback volume for a track, which should be set to 0 (zero) 
  248. if the track contains no sound.
  249.      "Media" refers to the actual data associated with a 
  250. particular track.  Each track can reference only one media, which 
  251. may reside within the movie file itself or on a storage device 
  252. such as CD ROM, remote server volume, or disk.  NewTrackMedia() 
  253. creates a media based on the supplied media data type (video, 
  254. animation, sound, etc.), time scale and data references.  The 
  255. last two parameters, dataRef and dataRefType, specify where the 
  256. actual data samples for the media are stored.    Since our samples 
  257. will be stored within the movie file itself, we pass nil for 
  258. both.
  259.      The new media has no data associated with it at this point.  
  260. Before adding the data (known as data samples  or samples) we 
  261. must inform the Movie Toolbox of our intentions. 
  262.      BeginMediaEdits() starts a media-editing session, notifying 
  263. the Movie Toolbox that we will be altering media.  Adding samples 
  264. must be done within a media-editing session started by 
  265. BeginMediaEdits() and concluded with EndMediaEdits().  We will be 
  266. adding several samples to the media, each a compressed QuickDraw 
  267. image representing a frame in the completed movie.
  268.  
  269. Making Frames
  270. MakeMovieGWorld() prepares the graphics enviroment, or GWorld, 
  271. into which we will draw our movie frames.  A GWorld is an 
  272. offscreen port and pixel map with associated offscreen memory.  
  273. GWorlds are allocated based on a supplied pixel depth and 
  274. rectangle.  We pass the deepest pixel depth our images might 
  275. have, along with the bounding rectandle of our largest movie 
  276. frame (which all happen to be the same size).  Passing the 
  277. maximum of each ensures that the GWorld allocated for our movie, 
  278. movieGWorld, will be able to accomodate the largest individual 
  279. frame.
  280.      We also need to allocate storage for the compressed frames, 
  281. since the compression routine requires a location in memory to 
  282. place the compressed image when finished. AllocateMovieBuffer() 
  283. sets aside enough memory to hold a single compressed movie frame.  
  284. To calculate how much memory is needed, a call to 
  285. GetMaxCompresionSize() is made with parameters describing what 
  286. type of compressor component to use and to what depth and quality 
  287. the image should be compressed:
  288.      
  289. OSErr GetMaxCompressionSize (PixMapHandle src, const Rect *srcRect, short colorDepth, CodecQ quality,                    CodecType cType, CompressorComponent codec, long *size)
  290.  
  291. A handle to our movieGWorld pixMap is passed as the source (src) 
  292. image.  The size and pixel depth of the source are used to 
  293. calculate the maximum possible size of the compressed image, 
  294. where srcRect specifies the portion of the source image to 
  295. compress.  No image compression is actually done, only a maximum 
  296. compressed image size is calculated. Using the compressed image 
  297. size, we allocate a frame buffer (frameDatabitsH) capable of 
  298. holding the largest possible compressed movie frame. 
  299.      For a detailed explaination of    the various 
  300. GetMaxCompressionSize() arguments, see "Details, Details" in this 
  301. article.
  302.  
  303. Adding Frame Samples to the Media
  304. After allocating our GWorld (movieGWorld ) and frame buffer 
  305. (frameDatabitsH ), we create the media samples.  Our media 
  306. samples are the individual graphic frames which make up the 
  307. movie.  [QuickTime 1.0 supports video, animation and sound 
  308. samples. Future versions of QuickTime are expected to 
  309. support custom defined data types, such as samples gathered from 
  310. special laboratory equipment.]
  311.      MakeMovieFrames() uses simple QuickDraw routines to create a 
  312. unique graphic image, or frame.  Each frame is copied to the 
  313. display window, providing visual feedback for the user.   
  314. AddMovieFrame() is then called, adding the individual frame to 
  315. the media.
  316.      AddMovieFrame()  compresses the current frame using 
  317. CompressImage(), the results of which are placed into the frame 
  318. buffer referenced by frameDatabitsH.  The compressed image    
  319. in frameDatabitsH is added to the media using AddMediaSample().  
  320. This process is repeated for every frame.
  321.  
  322. OSErr CompressImage (PixMapHandle src, const  Rect *srcRect, 
  323. CodecQ quality, CodecType                            
  324. cType, ImageDescriptionHandle desc, Ptr data)
  325.  
  326. OSErr AddMediaSample (Media m, Handle dataIn, long inOffset, 
  327. unsigned long size, TimeValue durationPerSample,                
  328. SampleDescriptionHandle sampleDescriptionH, long  
  329. numberOfSamples,                    short  
  330. sampleFlags, TimeValue *sampleTime)
  331.  
  332. For more information on AddMediaSample() see "Details, Details".  
  333. There you will also find several CompressImage() arguments 
  334. defined, as this call and GetMaxCompresionSize() share many of 
  335. the same parameters.
  336.  
  337. After all samples are created, compressed and added to the media 
  338. it is time to close shop.  Our media editing session is closed 
  339. with a call to EndMediaEdits().  The media is then added to the 
  340. movie track with InsertMediaIntoTrack() which specifies the track 
  341. into which to add the media, where the media segment should be 
  342. inserted (expressed in terms of the movie's time scale), the 
  343. starting point of the media segment  (expressed in terms of the 
  344. the media's time scale), the media segment's duration and the 
  345. media rate (1.0 indicates the natural playback rate of the 
  346. media).
  347.  
  348. OSErr InsertMediaIntoTrack (Track t, TimeValue trackStart, 
  349. TimeValue mediaTime, TimeValue mediaDuration, 
  350.                 Fixed mediaRate)
  351.  
  352. Next, the movie, track and media are saved as a resource in the 
  353. movie file. AddMovieResource() is passed the movie to add, the 
  354. movie file to add it to, and the name we wish to give the 
  355. resulting resource.  AddMovieResource() creates a resource of 
  356. type 'moov' in the resource fork of the file, returning its 
  357. resource id.  An unnamed resource is created if nil is passed as 
  358. the name.
  359.  
  360.  
  361. Preview 
  362. As a finishing touch we add a preview to our movie.  As discussed 
  363. earlier, a preview allows the user to see a thumbnail image of a 
  364. selected file prior to opening it (see figure 3).  Creating a 
  365. preview is simple, consisting of a single call:   
  366.      
  367. OSErr MakeFilePreview (short resRefNum, ProgressProcRecordPtr 
  368. progress)
  369.  
  370. This routine expects a resource reference number from which it 
  371. will make a PICT preview.  We pass the resource reference id of 
  372. our newly created 'moov' resource, obtained in a previous call to 
  373. AddMovieResource().  The second parameter to MakeFilePreview()  
  374. specifies a progress function used to keep the user informed of 
  375. the preview creation process.    Pass -1 (negative one)    to use 
  376. the system default or specify a custom progress routine of your 
  377. own.
  378.  
  379.  
  380.